package assignment1.eventplan.services;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.text.format.DateUtils;

import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import assignment1.eventplan.activity.DetailActivity;
import assignment1.eventplan.db.dao.EventPlanDao;
import assignment1.eventplan.db.master.EventPlanProvider;
import assignment1.eventplan.entity.EventPlan;
import assignment1.eventplan.request.MatrixRequestBuilder;
import assignment1.eventplan.request.MatrixResult;
import assignment1.eventplan.request.Request;
import assignment1.eventplan.request.Response;
import assignment1.eventplan.utils.DateUtil;
import assignment1.eventplan.utils.NotificationHelper;

/**
 * @author 陈晓辉
 * @description <>
 * @date 2016/10/8
 */
public class MapMatrixService extends Service {


    private AlarmServiceControllerImpl controller;

    @Override
    public void onCreate() {
        super.onCreate();
        controller = new AlarmServiceControllerImpl(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        controller.start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return controller;
    }


    private static class AlarmServiceControllerImpl extends Binder implements AlarmServiceController, LocationListener, Request.RequestListener {

        private static final int ONE_MINUTE = 60 * 1000;
        private final Service service;
        private LocationManager locationManager;

        AlarmServiceControllerImpl(Service alarmService) {
            this.service = alarmService;

        }

        public void start() {
            if (null == locationManager) {
                locationManager = (LocationManager) service.getSystemService(Context.LOCATION_SERVICE);
                locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, ONE_MINUTE/* in milliseconds */,
                        1 /* in meters */, this);
            } else {
                onLocationChanged(getLastKnownLocation());
            }
        }

        @Nullable
        @Override
        public Location getLastKnownLocation() {
            return null != locationManager ? locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) : null;
        }


        @Override
        public void onLocationChanged(@Nullable Location location) {
            if (null == location)
                return;
            List<EventPlan> planList = EventPlanProvider.get().getTodayPlans();
            if (null == planList)
                return;
            Iterator<EventPlan> planIterator = planList.iterator();
            while (planIterator.hasNext()) {
                EventPlan plan = planIterator.next();

                if (plan.getStartDateTime() - plan.getAlarmSeconds() * 1000/* millis */ - 2 * 60 * 1000/* permissible error */ > System.currentTimeMillis()) {
                    continue;
                }

                MatrixRequestBuilder.obtain()
                        .originAddress(location.getLatitude() + "," + location.getLongitude())
                        .destinationAddress(plan.getLatLng())
                        .request(plan.getId(), this);
            }
        }

        @Override
        public void onResponse(Request request, Response response) {
            if (response.isSuccessful()) {
                MatrixResult matrixResult = MatrixResult.obtain(response);
                try {
                    if (null != matrixResult.error) {
                        return;
                    }
                    final long eventId = request.getRequestId();
                    EventPlan plan = EventPlanProvider.get().getEventById(eventId);
                    if (null != plan
                            && plan.isActiveRequest(request.getSequence())
                            && matrixResult.getDurationValue() <= plan.getAlarmSeconds()
                            && DateUtil.isBefore(System.currentTimeMillis(), plan.getStartDateTime())) {
                        Intent intent = new Intent(service, DetailActivity.class);
                        intent.putExtra(EventPlanDao.Field.ID, plan.getId());
                        String ticker = String.format(Locale.getDefault(), "Notes! Now you driving to %s event just %d minutes!",
                                plan.getAddressName(), matrixResult.getDistanceValue() / 60);
                        NotificationHelper.notify(service, ticker, plan.getTitle(), plan.getNote(),
                                NotificationHelper.buildPendingIntentWithParentStack(service, intent), System.currentTimeMillis(), (int) plan.getId());
                    } else if (null != plan) {
                        NotificationHelper.build(service).cancel((int) plan.getId());
                    }
                } finally {
                    MatrixResult.recycle(matrixResult);
                }

            }
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

        }


    }


    public interface AlarmServiceController {


        @Nullable
        Location getLastKnownLocation();
    }
}
